package cn.gaosiy.thread;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Map;

/**
 * 随机访问文件线程
 * @author gaosiy
 */
public class RafThread extends Thread{

    /**
     * 开始位置
     */
    private long startPos;

    private long endPos;

    /**
     * 每个线程读取文件的大小
     */
    private long blockSize;

    /**
     * 需要读取的文件，可以是网络文件
     */
    private String readFile;

    /**
     * 需要写入的地址，需要是实体地址
     */
    private File writeFile;

    /**
     * 线程缓存区
     * 越大下载越快，但占用内存越高，且其每次下载量 <= blockSize
     */
    private int mbNum;

    /**
     * 文件类型
     */
    private int fileType;

    /**
     * 初始化参数
     * @param readFile 需要读取的文件
     * @param writeFile 需要写入的文件
     */
    public RafThread(String readFile, File writeFile, long startPos, long endPos, long blockSize, int mbNum, int fileType){
        this.readFile = readFile;
        this.writeFile = writeFile;
        this.startPos = startPos;
        this.blockSize = blockSize;
        this.mbNum = mbNum;
        this.fileType = fileType;
        this.endPos = endPos;
    }

    @Override
    public void run() {
        RandomAccessFile readRaf = null;
        RandomAccessFile writeRaf = null;
        HttpURLConnection conn = null;
        InputStream is = null;
        try {
            if(fileType == 1){
                URL url = new URL(readFile);
                conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(30000);
                conn.setRequestMethod("GET");
                //请求文件段
                System.out.println(Thread.currentThread().getName()+"网络分段下载: "+startPos+"-"+endPos);
                conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);
                conn.connect();
                long rLen = 0L;
                try {
                    rLen = Long.parseLong(conn.getHeaderField("Content-Length"));
                } catch (Exception e) {
                    rLen = -1;
                }
                int code = conn.getResponseCode();
                if((code == 200 || code == 206) && rLen > 0){
                    is = conn.getInputStream();
                    byte[] buf = new byte[1024 * 1024 * mbNum];
                    writeRaf = new RandomAccessFile(writeFile, "rw");
                    writeRaf.seek(startPos);
                    int len = -1;
                    while((len = is.read(buf)) > 0) {
                        writeRaf.write(buf, 0, len);
                    }
                    is.close();
                } else {
                    System.out.println("不支持分段下载");
                    Thread.yield();
                }
            } else {
                System.out.println(Thread.currentThread().getName()+"本地分段下载: "+startPos+"-"+endPos);
                readRaf = new RandomAccessFile(readFile,"r");
                readRaf.seek(startPos);

                writeRaf = new RandomAccessFile(writeFile,"rw");
                writeRaf.seek(startPos);
                writeRaf.setLength(writeFile.length());
                // 一次写入 mbNum MB
                byte[] buf = new byte[1024 * 1024 * mbNum];
                int len = -1;
                while((len = readRaf.read(buf)) > 0) {
                    writeRaf.write(buf, 0, len);
                }
            }
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if(writeRaf != null){
                try {
                    writeRaf.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                conn.disconnect();
            }
            Thread.yield();
        }
    }

}
